package astudy.parser.sql;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.Tree;

import astudy.antlr.ASTListener;
import astudy.antlr.ASTParser;
import astudy.antlr.EventManager;


public class QTemplate {

	static Map<Integer, String> tokens;
	static {
		tokens = getTokens();
	}

	public static void main(String[] args) throws Exception {

		long start = System.currentTimeMillis();
		testParser();
		System.out.println((System.currentTimeMillis() - start) + " ms");
	}
	
	private static void testParser() throws Exception {
		
		String filepath = null;
		CharStream stream = null;

		filepath = "TestParser.txt";
		URL url = QTemplate.class.getResource(filepath);
		File file = new File(URLDecoder.decode(url.getPath(), "UTF-8"));
		stream = new ANTLRFileStream(file.getAbsolutePath(), "UTF-8");
		
//		String sql = "with x as (select 'str''ing', a1  from a as a) select * from x order by 1 asc, 2 desc, 3 asc; select a from a;";
//		stream = new ANTLRStringStream(sql);
		Tree root = parse(stream, tokens);
		
		if (root != null) {
			String tmp = "";
			for (int i = 0; i < root.getChildCount(); i ++) {
				Tree query = root.getChild(i);
				tmp += new TreeStringParser().treeString(query);
			}
			System.out.println(tmp);
		}

	}
	
	private static Tree parse(CharStream stream, Map<Integer, String> tokens) 
	throws UnsupportedEncodingException, RecognitionException, IOException {
		
	    QTemplateLexer lex = new QTemplateLexer(stream);
	   	CommonTokenStream ts = new CommonTokenStream(lex);
	    QTemplateParser parser = new QTemplateParser(ts);

	    QTemplateParser.start_return ret = parser.start();
	    return (Tree)ret.getTree();
	}
	
	private static class TreeStringParser extends ASTParser {
		
		private EventManager em;
		private StringBuffer strQuery;
		private Set<String> tableNames;
		private Set<String> queryNames;
		
		public TreeStringParser() {

			strQuery = new StringBuffer("");
			tableNames = new HashSet<String>();
			queryNames = new HashSet<String>();
			
			//init
			initEventManager();
		}

		private void initEventManager() {
			em = new EventManager();
			em.append("*", new ASTListener() {

				public void process(Tree node) {
					int level = 0;
					Tree parent = node;
					while (parent != null && parent.getType() != QTemplateLexer.QueryNode) {
						level ++;
						parent = parent.getParent();
					}
					String indent = "";
					for (int i = 0; i < level; i ++) {
						indent += "\t";
					}
			    	strQuery.append(indent + node.getText() + "\n");
				}
			});
			
			em.append("QueryNode/SubQueryNode/NameNode", new ASTListener() {

				public void process(Tree nameNode) {
			
					String name = nameNode.getChild(0).getText().toUpperCase();
					queryNames.add(name);
				}
			});
			
			ASTListener tableNameListener = new ASTListener() {

				public void process(Tree nameNode) {
			
					String name = nameNode.getChild(0).getText().toUpperCase();
					if (!queryNames.contains(name)) {
						tableNames.add(name);
					}
				}
			};
			String[] patterns = new String[] {
					"QueryNode/SubQueryNode/SelectNode/TablesNode/TableNode/NameNode",
					"QueryNode/SelectNode/TablesNode/TableNode/NameNode",
					"QueryNode/SelectNode/TablesNode/LeftJoinNode/TableNode/NameNode",
					"QueryNode/SelectNode/TablesNode/RightJoinNode/TableNode/NameNode",
					"QueryNode/SelectNode/TablesNode/JoinNode/TableNode/NameNode"
			};
			for (String pattern: patterns) {
				em.append(pattern, tableNameListener);
			}
		}
		
		private String treeString(Tree node) {
			
			super.iterate(node, "QueryNode", this.em);
			
			String str = "";
			str += this.tableNames + "\n";
			str += strQuery.toString();
			str += "\n";
			return str;
		}
	}
	
	private static Map<Integer, String> getTokens() {

		BufferedReader br = null;
		try {
			Map<Integer, String> tokens = new HashMap<Integer, String>();
			URL url = QTemplate.class.getResource("QTemplate.tokens");
			File file = new File(URLDecoder.decode(url.getPath(), "UTF-8"));

			br = new BufferedReader(new FileReader(file));
			String line = null;
			while ((line = br.readLine()) != null) {
				String[] temp = line.split("=");
				tokens.put(Integer.valueOf(temp[1]), temp[0]);
			}
			br.close();
			
			return tokens;
		} catch (IOException e) {
			return null;
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}